home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / public / bit / src / jpeg.c < prev    next >
C/C++ Source or Header  |  1994-08-01  |  14KB  |  508 lines

  1. /*
  2.  * $Id: jpeg.c,v 0.91 1994/02/20 00:52:49 zhao Pre-Release $
  3.  *
  4.  *. This file is part of BIT shareware package. After the two weeks of
  5.  *  free evaluation period, you are encouraged (required) to register
  6.  *  your copy for a small registration fee, which is $35 for personal use
  7.  *  and $50 for commercial, government and institutional use.
  8.  *
  9.  *  Copyright(c) 1993, 1994 by T.C. Zhao.
  10.  *  All rights reserved.
  11.  *
  12.  *  Permission to use, copy, and distribute this software in its entirety
  13.  *  for non-commercial purposes is hereby granted, provided that the
  14.  *  above shareware and copyright notices and this permission notice
  15.  *  appear in all copies and their documentation.
  16.  *
  17.  *  This software may be modified for your own use, but modified versions
  18.  *  may not be distributed without prior consent of the author.
  19.  *
  20.  *  This software is provided "as is" without expressed or implied
  21.  *  warranty of any kind.
  22.  *
  23.  *.
  24.  *
  25.  * JPEG(JFIF) related routines are based in part on the work of
  26.  * the Independent JPEG Group. Also uses the Independent JPEG Group's
  27.  * library. See related files in jpeg directory for more details.
  28.  */
  29. #ifndef NO_JPEG
  30.  
  31. #if !defined(lint) && defined(F_ID)
  32. char *id_jpg = "$Id: jpeg.c,v 0.91 1994/02/20 00:52:49 zhao Pre-Release $";
  33. #endif
  34.  
  35. #include "bit.h"
  36. #include <stdlib.h>        /* exit prototype */
  37. #include "jinclude.h"
  38.  
  39. /* const may or may not be defined to be empty by jinclude.h */
  40. #ifdef Const
  41. #undef const
  42. #endif
  43.  
  44. #include <setjmp.h>
  45.  
  46.  
  47. /******** Decompression parameters: always output RGB *************/
  48.  
  49. static int jpg_quant = 0;    /* set to # of colors  */
  50. static int jpg_blksm = 0;    /* block smoothing     */
  51.  
  52. /******* compression parameters: all used  **************************/
  53.  
  54. static int jpeg_qval = 75;    /* default Q-value           */
  55. static int jpeg_sval = 0;    /* default smoothing factor  */
  56. static int jpeg_opt = 0;    /* optimize                  */
  57.  
  58. /******** some bit control parameters *********************************/
  59.  
  60. static int sofar, isjwrite;    /* line read and io id          */
  61. static jmp_buf jpg_jmp;        /* error recoveraty jump buffer */
  62. static IPTR jpg_current;    /* local copy of image pointer  */
  63. static long jpg_rlines;        /* reporting control            */
  64.  
  65. static int read_JPEG_file(FILE *);
  66. static int write_JPEG_file(FILE *);
  67.  
  68. /*******************************************************************
  69.  * One liner summary of JPEG output options
  70.  ******************************************************************/
  71.  
  72. /* ARGSUSED */
  73. const char *
  74. JPEG1_wdefault(const IPTR ip)
  75. {
  76.     static char rep[30];
  77.     sprintf(rep, "Q=%d  Smooth=%d", jpeg_qval, jpeg_sval);
  78.     return rep;
  79. }
  80.  
  81. /*****************************************************************
  82.  * Solicit output options
  83.  ****************************************************************/
  84.  
  85. /* ARGSUSED */
  86. int
  87. JPEG1dump_init(IPTR im)
  88. {
  89.     (void) get2int("Q value", &jpeg_qval, 5, 100,
  90.            "Smooth", &jpeg_sval, 0, 100,
  91.            "Optimize", &jpeg_opt, HELP_JPEG, 0);
  92.     return 0;
  93. }
  94.  
  95. /*********************************************************************
  96.  * The entry point for writing
  97.  *********************************************************************/
  98. int
  99. JPEG1_dump(IPTR img)
  100. {
  101.     sofar = 0;
  102.     jpg_current = img;
  103.     isjwrite = 1;
  104.     return write_JPEG_file(img->fp);
  105. }
  106.  
  107. /*
  108.  * the use of the canned library sort of breaks down the systematic approach
  109.  * of the BIT program as both the BIT program and the library want to take
  110.  * control. Have to fake description because we do not want to know too many
  111.  * details of the file format, the consequence of this is that the loading
  112.  * routine will have to do the memoery allocation explicitly.
  113.  */
  114.  
  115. int
  116. JPEG1_desc(IPTR im)
  117. {
  118.     /* fake the size to 1X1 to signal info reporting func  */
  119.     jpg_current = im;
  120.     jpg_current->w = 1;
  121.     jpg_current->h = 1;
  122.     jpg_current->esize = 4;
  123.     jpg_current->type = T_RGBA;
  124.     return 0;
  125. }
  126.  
  127. int
  128. JPEG1_load(IPTR im)
  129. {
  130.  
  131.     if (jpg_current != im)
  132.       {
  133.       Bark("JpegLoad", "Internal error");
  134.       return -1;
  135.       }
  136.  
  137.     isjwrite = sofar = 0;
  138.  
  139.     if (read_JPEG_file(im->fp) < 0)
  140.     return -1;
  141.     if (im->type != T_GRAY)
  142.     im->type = T_RGBA;
  143.     return sofar;
  144. }
  145.  
  146. static external_methods_ptr emethods;
  147. METHODDEF void
  148. trace_message(const char *msgtext)
  149. {
  150.     /*
  151.      * error messages may have in it the file name, which could be
  152.      * MAXDLEN+MAXFLEN long. Really wish there were something line an
  153.      * snprintf
  154.      */
  155.     char errmsg[MAXFLEN + MAXDLEN], *p;
  156.     const char *func = isjwrite ? "JPG_write" : "JPG_read";
  157.  
  158.     /* wish there were an snprintf */
  159.     sprintf(errmsg, msgtext,
  160.         emethods->message_parm[0], emethods->message_parm[1],
  161.         emethods->message_parm[2], emethods->message_parm[3],
  162.         emethods->message_parm[4], emethods->message_parm[5],
  163.         emethods->message_parm[6], emethods->message_parm[7]);
  164.  
  165.     /* break long lines (otherwise clipped by GL) */
  166.     if (strlen(errmsg) < 40)
  167.       {
  168.       Bark(func, "%s:%s", jpg_current->ifile, errmsg);
  169.       }
  170.     else
  171.       {                /* break it at space */
  172.       if ((p = strchr(errmsg + 15, ' ')))
  173.           *p = '\n';
  174.       Bark(func, "%s:%s", jpg_current->ifile, errmsg);
  175.       }
  176. }
  177.  
  178. /* really do not what to exit, rather transfer control to main driver */
  179. METHODDEF void
  180. error_exit(const char *msgtext)
  181. {
  182.     trace_message(msgtext);    /* report the error message */
  183.     (*emethods->free_all) ();    /* clean up memory allocation & temp files */
  184.     longjmp(jpg_jmp, 1);    /* return control to outer routine */
  185.  
  186. }
  187.  
  188. METHODDEF void
  189. output_init(decompress_info_ptr info)
  190. {
  191.     jpg_current->w = info->image_width;
  192.     jpg_current->h = info->image_height;
  193.  
  194.     jpg_rlines = progress_report("Loading JPEG ...", jpg_current->h);
  195.     if (info->out_color_space == CS_GRAYSCALE)
  196.     jpg_current->type = T_GRAY;
  197.     else if (info->out_color_space == CS_RGB)
  198.     jpg_current->type = T_RGBA;
  199.     else
  200.       {                /* unecessary unless the driver screwed-up */
  201.       Bark("JPG_load", "%s: Bad Colorspace", jpg_current->ifile);
  202.       }
  203.  
  204.     /* always converts to RGB by load */
  205.     update_image_info(jpg_current);
  206.     if (img_get_rastermem(jpg_current) < 0)
  207.     longjmp(jpg_jmp, 1);
  208. }
  209.  
  210. METHODDEF void
  211. put_pixel_rows(decompress_info_ptr info, int num_rows,
  212.            JSAMPIMAGE pixel_data)
  213. {
  214.     register rgba_t *rgba;
  215.     register JSAMPROW ptr0, ptr1, ptr2, ptr;
  216.     register int row;
  217.     register int width = info->image_width;
  218.     register int height = info->image_height;
  219.  
  220. #ifdef V4A
  221.     /*
  222.      * it would appear that V4a's code might produce more scanlines than they
  223.      * are. Check here
  224.      */
  225.  
  226.     if ((num_rows + sofar) > height)
  227.       {
  228.       num_rows = height - sofar;
  229.       M_warn("OutputRows", "sofar=%d height=%d num_rows=%d\n",
  230.          sofar, height, num_rows);
  231.       }
  232. #endif
  233.  
  234.     if (info->out_color_space == CS_RGB)
  235.       {
  236.       for (row = 0; row < num_rows; row++, sofar++)
  237.         {
  238.         rgba = ((rgba_t **) jpg_current->mraster)[height - 1 - sofar];
  239.         ptr0 = pixel_data[0][row];
  240.         ptr1 = pixel_data[1][row];
  241.         ptr2 = pixel_data[2][row];
  242.         ptr = ptr0 + width;
  243.         for (; ptr0 < ptr; ptr0++, ptr1++, ptr2++)
  244.           {
  245.               *rgba++ = Pack(*ptr0, *ptr1, *ptr2);
  246.           }
  247.         REPORT(sofar, jpg_rlines);
  248.         }
  249.       }
  250.     else if (info->out_color_space == CS_GRAYSCALE)
  251.       {
  252.       for (row = 0; row < num_rows; row++, sofar++)
  253.         {
  254.         rgba = ((rgba_t **) jpg_current->mraster)[height - 1 - sofar];
  255.         ptr0 = ptr = pixel_data[0][row];
  256.         for (ptr = ptr0 + width; ptr0 < ptr; ptr0++)
  257.           {
  258.               *rgba++ = Pack(*ptr0, *ptr0, *ptr0);
  259.           }
  260.         REPORT(sofar, jpg_rlines);
  261.         }
  262.       }
  263.  
  264. }
  265.  
  266. /*
  267.  * color map is ready assigned in put_color_map
  268.  */
  269. /* ARGSUSED */
  270. METHODDEF void
  271. put_cmap_rows(decompress_info_ptr info, int num_rows,
  272.           JSAMPIMAGE pixel_data)
  273. {
  274.     register rgba_t *rgba, *rs, *mrgb = jpg_current->cmap->p_h.rgba;
  275.     register JSAMPROW ptr;
  276.     register int row;
  277.     register int width = jpg_current->w, height = jpg_current->h;
  278.  
  279.     for (row = 0; row < num_rows; row++, sofar++)
  280.       {
  281.       ptr = pixel_data[0][row];
  282.       rgba = ((rgba_t **) jpg_current->mraster)[height - 1 - sofar];
  283.       for (rs = rgba + width; rgba < rs;)
  284.         {
  285.         *rgba++ = mrgb[*ptr++];
  286.         }
  287.       REPORT(sofar, jpg_rlines);
  288.       }
  289. }
  290.  
  291. METHODDEF void
  292. put_color_map(decompress_info_ptr info, int num_colors,
  293.           JSAMPARRAY cm)
  294. {
  295.     int i, j;
  296.  
  297.     jpg_current->type = T_CMAP;
  298.     jpg_current->cmap->colors = num_colors;
  299.     for (j = 0; j < info->color_out_comps; j++)
  300.       {
  301.       for (i = 0; i < num_colors; i++)
  302.         {
  303.         jpg_current->cmap->ct[j][i] = cm[j][i];
  304.         }
  305.       }
  306.  
  307.     info->methods->put_pixel_rows = put_cmap_rows;;
  308.     if (info->color_out_comps == 1)
  309.       {                /* grap scale */
  310.       for (i = 0; i < num_colors; i++)
  311.           jpg_current->cmap->p_h.rgba[i] = Pack(cm[0][i], cm[0][i], cm[0][i]);
  312.       jpg_current->cmap->packed = 1;
  313.       }
  314.     else if (info->color_out_comps == 3)
  315.       {
  316.       pack_cmap(jpg_current->cmap);
  317.       }
  318.     else
  319.       {
  320.       Bark("JPG_load", "%s: BadColorComponent", jpg_current->ifile);
  321.       longjmp(jpg_jmp, 1);
  322.       }
  323. }
  324.  
  325. /* ARGSUSED */
  326. METHODDEF void
  327. output_term(decompress_info_ptr info)
  328. {
  329.     remove_progress_report();
  330. }
  331.  
  332.  
  333. METHODDEF void
  334. d_ui_method_selection(decompress_info_ptr info)
  335. {
  336.     if (info->jpeg_color_space == CS_GRAYSCALE)
  337.     info->out_color_space = CS_GRAYSCALE;
  338.     info->methods->output_init = output_init;
  339.     info->methods->put_color_map = put_color_map;
  340.     info->methods->put_pixel_rows = put_pixel_rows;
  341.     info->methods->output_term = output_term;
  342. }
  343.  
  344. static int
  345. read_JPEG_file(FILE * fp)
  346. {
  347.  
  348.     static struct Decompress_info_struct dcinfo;
  349.     static struct Decompress_methods_struct dc_methods;
  350.     static struct External_methods_struct e_methods;
  351.  
  352.     dcinfo.input_file = fp;
  353.     dcinfo.output_file = NULL;    /* if no actual output file involved */
  354.  
  355.     dcinfo.methods = &dc_methods;    /* links to method structs */
  356.     dcinfo.emethods = &e_methods;
  357.     emethods = &e_methods;    /* save struct addr for possible access */
  358.  
  359.     e_methods.trace_message = trace_message;
  360.     e_methods.error_exit = error_exit;    /* supply error-exit routine */
  361.  
  362.     e_methods.trace_level = 0;
  363.     e_methods.num_warnings = 0;
  364.     e_methods.first_warning_level = 0;
  365.     e_methods.more_warning_level = 3;
  366.  
  367.     if (setjmp(jpg_jmp))
  368.       {
  369.       remove_progress_report();
  370.       return sofar;
  371.       }
  372.     jselmemmgr(&e_methods);    /* select std memory allocation routines */
  373.  
  374.     dc_methods.d_ui_method_selection = d_ui_method_selection;
  375.     dcinfo.desired_number_of_colors = jpg_quant;
  376.  
  377.     /* quantize only if sensible number of color is requested */
  378.     dcinfo.quantize_colors = jpg_quant > 10;
  379.  
  380.     dcinfo.do_block_smoothing = jpg_blksm;
  381.     j_d_defaults(&dcinfo, TRUE);
  382.     jselrjfif(&dcinfo);
  383.  
  384.  
  385. #ifdef MTRACE
  386.     M_trace("ReadJpeg", "Right before decompress");
  387. #endif
  388.     jpeg_decompress(&dcinfo);
  389.     return sofar;
  390. }
  391.  
  392. /*
  393.  * compressing routines
  394.  */
  395. METHODDEF void
  396. input_init(compress_info_ptr info)
  397. {
  398.     info->image_width = jpg_current->w;
  399.     info->image_height = jpg_current->h;
  400.     if (jpg_current->type == T_GRAY)
  401.       {
  402.       info->input_components = 1;
  403.       info->in_color_space = CS_GRAYSCALE;
  404.       }
  405.     else
  406.       {
  407.       info->in_color_space = CS_RGB;
  408.       info->input_components = 3;
  409.       }
  410.     info->data_precision = PCBITS;    /* bits per pixel component value */
  411.     jpg_rlines = progress_report("Writing JPEG ...", jpg_current->h);
  412. }
  413.  
  414. METHODDEF void
  415. get_input_row(compress_info_ptr info, JSAMPARRAY pixel_row)
  416. {
  417.     register JSAMPROW ptr0, ptr1, ptr2;
  418.     register int col, r, g, b;
  419.     register rgba_t *rgba, *rend;
  420.  
  421.     rgba = ((rgba_t **) jpg_current->mraster)[jpg_current->h - 1 - sofar];
  422.     if (jpg_current->type == T_RGBA)
  423.       {
  424.       ptr0 = pixel_row[0];
  425.       ptr1 = pixel_row[1];
  426.       ptr2 = pixel_row[2];
  427.       for (rend = rgba + info->image_width; rgba < rend; rgba++)
  428.         {
  429.         Unpack(*rgba, r, g, b);
  430.         *ptr0++ = (JSAMPLE) r;
  431.         *ptr1++ = (JSAMPLE) g;
  432.         *ptr2++ = (JSAMPLE) b;
  433.         }
  434.       REPORT(sofar, jpg_rlines);
  435.       sofar++;
  436.       }
  437.     else if (jpg_current->type == T_GRAY)
  438.       {
  439.       ptr0 = pixel_row[0];
  440.       for (col = 0; col < info->image_width; col++)
  441.         {
  442.         r = (*rgba & 0xff);
  443.         *ptr0++ = (JSAMPLE) r;
  444.         rgba++;
  445.         }
  446.       REPORT(sofar, jpg_rlines);
  447.       sofar++;
  448.       }
  449. }
  450.  
  451. /* ARGSUSED */
  452. METHODDEF void
  453. input_term(compress_info_ptr info)
  454. {
  455.     remove_progress_report();
  456. }
  457.  
  458. METHODDEF void
  459. c_ui_method_selection(compress_info_ptr info)
  460. {
  461.     if (info->in_color_space == CS_GRAYSCALE)
  462.     j_monochrome_default(info);
  463.     jselwjfif(info);
  464. }
  465.  
  466. static int
  467. write_JPEG_file(FILE * fp)
  468. {
  469.     static struct Compress_info_struct cinfo;
  470.     static struct Compress_methods_struct c_methods;
  471.     static struct External_methods_struct e_methods;
  472.  
  473.     cinfo.emethods = &e_methods;
  474.     cinfo.methods = &c_methods;    /* links to method structs */
  475.     emethods = &e_methods;    /* save struct addr for possible access */
  476.     e_methods.error_exit = error_exit;    /* supply error-exit routine */
  477.     e_methods.trace_message = trace_message;
  478.     jselmemmgr(&e_methods);    /* select std memory allocation routines */
  479.     c_methods.input_init = input_init;
  480.  
  481.     if (setjmp(jpg_jmp))
  482.       {
  483.       remove_progress_report();
  484.       fclose(cinfo.output_file);
  485.       return sofar;
  486.       }
  487.  
  488.     c_methods.get_input_row = get_input_row;
  489.     c_methods.input_term = input_term;
  490.     c_methods.c_ui_method_selection = c_ui_method_selection;
  491.     cinfo.input_file = NULL;    /* if no actual input file involved */
  492.     cinfo.output_file = fp;
  493.  
  494.     /* permitted compression options */
  495.     j_c_defaults(&cinfo, jpeg_qval, FALSE);
  496.     cinfo.smoothing_factor = jpeg_sval;
  497.     cinfo.optimize_coding = jpeg_opt;
  498.  
  499. #ifdef MTRACE
  500.     M_trace("ReadJpeg", "Right before compress");
  501. #endif
  502.     jpeg_compress(&cinfo);
  503.     fflush(cinfo.output_file);
  504.     return sofar;
  505. }
  506.  
  507. #endif
  508.